package com.pinyougou.search.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.pinyougou.es.EsItem;
import com.pinyougou.search.dao.EsItemDao;
import com.pinyougou.service.ItemSearchService;
import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.facet.FacetRequest;
import org.springframework.data.elasticsearch.core.query.DeleteQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ItemSearchServiceImpl implements ItemSearchService {
    @Autowired
    private ElasticsearchTemplate esTemplate;
    @Autowired
    private EsItemDao esItemDao;



    /** 搜索方法 */
    @Override
    public Map<String, Object> search(Map<String,Object> params) {

        /** 获取查询关键字 */
        String keywords = (String)params.get("keywords");

        // 创建原生的搜索条件构建对象
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        // 设置默认搜索全部
        builder.withQuery(QueryBuilders.matchAllQuery());

        /** 判断检索关键字是否为空 */
        if (StringUtils.isNoneBlank(keywords)) {
            // 设置根据多条件查询
            builder.withQuery(QueryBuilders.multiMatchQuery(keywords,"title","category","brand","seller"));
            //创建高亮字段对象
            HighlightBuilder.Field field = new HighlightBuilder
                    .Field("title") //需要高亮的字段
                    .preTags("<font color='red'>")//设置高亮前缀
                    .postTags("</font>")//高亮后缀
                    .fragmentSize(50);//设置文本截断
            builder.withHighlightFields(field);
        }

        /** ########## 搜索过滤 ########### */
        //创造组合查询构造对象,封装多个过滤条件
        BoolQueryBuilder boolBuilder = QueryBuilders.boolQuery();
        //组合多个过滤条件(必须的方式组合)

        //商品分类过滤
        String category = (String) params.get("category");
        if (StringUtils.isNoneBlank(category)){
            //词条查询
            boolBuilder.must(QueryBuilders.termQuery("category",category));
        }
        //按照商品品牌过滤
        String brand = (String) params.get("brand");
        if (StringUtils.isNoneBlank(brand)){
            //词条查询
            boolBuilder.must(QueryBuilders.termQuery("brand",brand));
        }
        //按照商品规格过滤
        Map<String,String> specMap = (Map<String, String>) params.get("spec");
        if (specMap != null && specMap.size() > 0){
            // { "网络": "联通3G", "机身内存": "128G" }
            for (String key : specMap.keySet()) {
                // 嵌套Field的名称
                String field = "spec." + key + ".keyword";
                // 必须的方式(嵌套查询)
                // String path, QueryBuilder query, ScoreMode scoreMode
                boolBuilder.must(QueryBuilders.nestedQuery("spec",
                        QueryBuilders.termQuery(field, specMap.get(key)), ScoreMode.None));
            }
        }
        //按商品价格区间过滤
        String price = (String) params.get("price");
        if (StringUtils.isNoneBlank(price)){
            //得到价格区域间数组
            String[] priceArr = price.split("-");
            //范围查询构造对象
            RangeQueryBuilder rqBuilder = QueryBuilders.rangeQuery("price");
            //如果结束价格为星号
            if ("*".equals(priceArr[1])){
                //大于起始价格3000-*
                rqBuilder.gt(priceArr[0]);
            }else {
                //从起始价格到结束价格
                rqBuilder.from(priceArr[0]).to(priceArr[1]);
            }
            //组合范围查询
            boolBuilder.must(rqBuilder);
        }
        //添加过滤条件
        builder.withFilter(boolBuilder);


        // 构建搜索查询对象
        SearchQuery query = builder.build();
        /**  ############# 分页查询 ########### */
        // 分页查询，得到合计分页对象
        Integer curPage = (Integer) params.get("page");
        if (category==null){
            curPage=1;
        }
        /*##################排序查询####################*/
        //获取排序参数
        String sortValue = (String) params.get("sortValue"); //ASC DESC
        String  sortFiled = (String) params.get("sortField");//排序字段
        if (StringUtils.isNoneBlank(sortValue)&&StringUtils.isNoneBlank(sortFiled)){
            //创建排序对象
            Sort sort = new Sort("ASC".equalsIgnoreCase(sortValue)?Sort.Direction.ASC : Sort.Direction.DESC,sortFiled);
            //设置添加排序
            query.addSort(sort);
        }

        //设置分页对象(注意,页码从0开始)
        query.setPageable(PageRequest.of(curPage -1 ,20));
        AggregatedPage<EsItem> page = esTemplate
                .queryForPage(query, EsItem.class,
                        new SearchResultMapper() {//搜索结果转换
                            @Override
                            public <T> AggregatedPage<T> mapResults(SearchResponse sr, Class<T> aClass, Pageable pageable) {
                                //定义list集合封装分页结果
                                List<T> content = new ArrayList<>();
                                //循环封装分页结果
                                for (SearchHit hit : sr.getHits()) {
                                    //获取搜索的文档json,转化成EsItem
                                    EsItem esItem = JSON.parseObject(hit.getSourceAsString(), EsItem.class);
                                    //获取标题高亮对象
                                    HighlightField highlightField = hit.getHighlightFields().get("title");
                                    //判断是否有标题高亮对象
                                    if (highlightField !=null){
                                        //获取标题高亮内容字符串
                                        String title = highlightField.getFragments()[0].toString();
                                        //设置标题高亮内容
                                        esItem.setTitle(title);
                                    }
                                    //添加到新集合
                                    content.add((T)esItem);
                                }
                                return new AggregatedPageImpl<>(content,pageable,sr.getTotalShards());
                            }
                        });



        // 定义Map集合封装返回数据
        Map<String,Object> data = new HashMap<>();
        // 设置总记录数
        data.put("total", page.getTotalElements());
        // 设置分页结果
        data.put("rows", page.getContent());
        //设置总页数
        data.put("totalPages",page.getTotalPages());
        return data;
    }


    public void saveOrUpdate(List<EsItem> esItems) {
        try {
            esItemDao.saveAll(esItems);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void delete(List<Long> goodsIds) {
        try {
            DeleteQuery dq =new DeleteQuery();
            dq.setIndex("pinyougou");
            dq.setType("item");
            dq.setQuery(QueryBuilders.termsQuery("goodsId",goodsIds));
            esTemplate.delete(dq);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}
